#pragma once
# include <string>
# include <thread>
# include <iostream>
# include "Formater.h"
# include "Logger.h"
# include <vector>
# include <functional>
# include "Enums.h"

# define debug(...) log_debug(__FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
# define info(...) log_info(__FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
# define warn(...) log_warn(__FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
# define error(...) log_error(__FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)

namespace ZDSJ {
	class Formater;
	class LogStreamInterface;

	class Log {
		
	public:
		Log();

		Log(const std::string& _formater);
		Log(const Formater& _formater);

		Log(Level _level, const std::string& _formater);
		Log(Level _level, const Formater& _formater);

		~Log();

		void setTimeFormate(const std::string& _formate);

		std::string getTimeFormate() const;

		void setFileLevel(int _file_level);

		int getFileLevel() const;

		void addStream(const LogStreamInterface* _stream);

		template <typename ... Args>
		void log_debug(const std::string& _file_name, int _line, const std::string& _func_name, Args && ... _args) {
			if (this->m_level > Level::debug) {
				return;
			}
			this->m_logger->work(this->m_formater->writeLog(this->getTime(), "DEBUG", this->dealFileName(_file_name), _func_name, _line, std::this_thread::get_id(), std::forward<Args>(_args)...), 
			this->m_works);
		}

		template <typename ... Args>
		void log_info(std::string _file_name, int _line, std::string _func_name, Args && ... _args) {
			if (this->m_level > Level::debug) {
				return;
			}
			// this->m_formater->writeLog();
		}

		template <typename ... Args>
		void log_warn(std::string _file_name, int _line, std::string _func_name, Args && ... _args) {
			if (this->m_level > Level::debug) {
				return;
			}
			// this->m_formater->writeLog();
		}

		template <typename ... Args>
		void log_error(std::string _file_name, int _line, std::string _func_name, Args && ... _args) {
			if (this->m_level > Level::debug) {
				return;
			}
			// this->m_formater->writeLog();
		}

	private:
		Formater* m_formater = nullptr;
		std::string m_time_format = "%Y-%m-%d";
		int m_file_level = 1;
		Level m_level = Level::debug;
		Logger* m_logger = Logger::getInstance();
		std::vector<LogStreamInterface*> m_works;

		std::string getTime();
		std::string dealFileName(const std::string& _file_name);
	};

}
